<?php
namespace App\Services\System;

use App\Models\System\Permission as SystemPermission;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Cache;

/**
 * 系统权限服务类
 * @package App\Services
 */
class Permission
{
    /**
     * 面包屑数据
     * @var
     */
    private $breadcrumbData = [];
    /**
     * 构造函数
     */
    public function __construct()
    {
    }

    public function getPermList($isRefresh = false)
    {
        $cacheKey = '';
        $permissions = SystemPermission::with('roles')->get();
        $permissions = $permissions ? $permissions->toArray() : [];
    }

    /**
     * 获取所有权限列表
     * @return mixed
     */
    public function getAllList()
    {
        $permList = SystemPermission::orderBy('order_num','ASC')->orderBy('perm_id','ASC')->get()->toArray();
        $newPermList = [];
        if ($permList){
            foreach ($permList as $v){
                $newPermList[(int) $v['perm_id']] = $v;
            }
        }
        return $newPermList;
    }

    /**
     * 获取指定权限下的权限列表
     * @param $parentId
     * @return mixed
     */
    public function getChildList($parentId)
    {
        $permList = SystemPermission::where('parent_id', $parentId)->orderBy('order_num','ASC')->orderBy('perm_id','ASC')->get()->toArray();
        return $permList;
    }

    /**
     * 获取数据
     * @param $permId
     * @return mixed
     */
    public function getData($permId)
    {
        return SystemPermission::findOrFail($permId)->toArray();
    }

    /**
     * 通过路由名称（权限定义）获取权限数据
     * @param $permName
     * @return mixed
     */
    public function getDataByPermName($permName)
    {
        $find = SystemPermission::where('name', $permName)->orderBy('perm_id','desc')->first();
        return $find ? $find->toArray() : ['perm_id'=>0,'name'=>'','display_name' => ''];
    }

    /**
     * 通过路由名称（权限定义）获取权限数据(缓存版)
     * @param $permName
     * @return mixed
     */
    public function getDataByPermNameInCache($permName)
    {
        return $this->getCacheSimplePermDataByName($permName);
        /*$permList = $this->getCachePermList();
        $collection = collect($permList);
        return $collection->last(function ($value, $key) use ($permName) {
            return $value['name'] == $permName;
        });*/
    }

    /**
     * 保存添加权限
     * @param $saveData
     * @return bool
     */
    public function saveData($saveData)
    {
        if (!empty($saveData['perm_id'])){
            $perm = SystemPermission::find($saveData['perm_id']);
        }else{
            $perm = new SystemPermission;
        }
        $perm->parent_id = $saveData['parent_id'] ?? 0;
        $perm->name = $saveData['name'] ?? '';
        $perm->display_name = $saveData['display_name'] ?? '';
        $perm->description = (string) ($saveData['description'] ?? '');
        $perm->is_public = (int) ($saveData['is_public'] ?? 0);
        $perm->is_opertion_log = (int) ($saveData['is_opertion_log'] ?? 0);
        $perm->order_num = (int) ($saveData['order_num'] ?? 0);
        $rs = $perm->save();
        //$rs && $this->clearPermListCache();
        $rs && $this->getCacheSimplePermList(true);
        return $rs;
    }

    /**
     * 删除
     * @param $permId
     * @return mixed
     */
    public function del($permIds)
    {
        $list = SystemPermission::query()->where('perm_id','in', $permIds)->get();
        $rs = SystemPermission::destroy($permIds);
        //$rs && $this->clearPermListCache();
        if ($rs){
            $this->getCacheSimplePermList(true);
            if ($list){
                foreach ($list as $v){
                    $this->getCacheSimplePermDataById($v['perm_id']);
                    $this->getCacheSimplePermDataByName($v['name']);
                }
            }
        }
        return $rs;
    }

    /**
     * 保存排序
     * @param $parentId
     * @param $ruleId
     * @param $position
     * @return bool
     * @throws \Exception
     */
    public function setOrder($draggingNode, $dropNode, $dropType)
    {
        switch($dropType){
            case 'before'://拖拽到某个节点之前
            case 'after'://拖拽到某个节点之后
                DB::beginTransaction();
                try{
                    //拖拽节点更改排序数字及父级分类
                    if ($dropType == 'before') {
                        $newOrderNum = $dropNode['order_num'] ?? 0;
                    }else{
                        $newOrderNum = $dropNode['order_num'] ? $dropNode['order_num'] + 1 : 0;
                    }
                    //调整之后节点的排序数字,之后的节点各加2，为插入节点留空隙
                    $sameLevelPermList = $this->getChildList($dropNode['parent_id']);
                    //拖拽节点更改排序数字及父级分类
                    SystemPermission::query()->find($draggingNode['perm_id'])->update(['parent_id' => $dropNode['parent_id'], 'order_num' => $newOrderNum]);

                    $isStartSet = false;
                    foreach ($sameLevelPermList as $permData){
                        if ($permData['perm_id'] == $dropNode['perm_id']){//从放置节点开始后续排序自动加一
                            $isStartSet = true;
                            if ($dropType == 'after'){//插入到后面，则被放置节点不处理
                                continue;
                            }
                            if ($dropType == 'before'){//插入到前面，从被放置节点开始排序开始调整

                            }
                        }
                        if ($isStartSet && $permData['perm_id'] != $draggingNode['perm_id']){
                            $newOrderNum++;
                            SystemPermission::query()->find($permData['perm_id'])->update(['order_num' => $newOrderNum]);
                        }
                    }
                    DB::commit();
                }catch (\Exception $e){
                    DB::rollBack();
                    throw new \Exception($e->getMessage());
                }
                break;
            case 'inner'://拖进节点，直接更改父级ID
                SystemPermission::query()->find($draggingNode['perm_id'])->update(['parent_id' => $dropNode['perm_id']]);
                break;
            default:
                throw new \Exception('无效的拖拽类型');
        };
        //清除缓存
        //$this->clearPermListCache();
        return true;
    }
    /**
     * 附加权限的角色数据
     * @param array $permList
     */
    protected function attachPermRoleData($permList = [])
    {
        //获取拼有权限的角色列表
        $roleList = (new \App\Services\System\Role())->getAllRoleWithPermList();
        //将角色以权限ID分组
        $roleGroupList = collect($roleList)->groupBy('perm_id');
        //将包含权限的角色列表包含进每项中
        $permList->transform(function ($item, $key) use ($roleGroupList) {
            $roles = $roleGroupList->get($item->perm_id);
            $item->roles = json_decode(json_encode($roles), true);
            return $item;
        });
        return $permList;
    }
    /**
     * 获取权限定义服务提供器中用到的权限列表
     * @param bool $isRefresh 是否强制刷新
     * @return array
     */
    public function getCachePermList($isRefresh = false)
    {
        $cacheKey = 'syspermission:permlist';
        $cacheData = Cache::get($cacheKey);
        if (!$cacheData || $isRefresh) {
            //$cacheData = \App\Models\System\SystemPermission::with('roles:name')->select(['perm_id','name', 'is_public'])->get();
            $cacheData = \App\Models\System\Permission::query()->select(['perm_id', 'parent_id','name','display_name', 'order_num', 'is_public'])->get();
            //附加上权限的角色数据
            $cacheData = $this->attachPermRoleData($cacheData);
            //装换为数组
            $cacheData = $cacheData ? $cacheData->toArray() : [];
            //以权限ID为KEY
            if ($cacheData){
                $newCacheData = [];
                foreach ($cacheData as $v){
                    $newCacheData[(int) $v['perm_id']] = $v;
                }
                $cacheData = $newCacheData;
            }
            Cache::put($cacheKey, $cacheData, Carbon::now()->addMinutes(60));
        }
        //附加上权限拥有角色列表
        return $cacheData;
    }

    /**
     * 清除权限列表缓存
     */
    public function clearPermListCache()
    {
        $cacheKey = 'syspermission:permlist';
        Cache::delete($cacheKey);
    }

    /**
     * 获取轻巧版权限列表
     * @param false $isRefresh
     * @return array|mixed
     */
    public function getCacheSimplePermList($isRefresh = false)
    {
        $cacheKey = 'syspermission:permlist_simple';
        $cacheData = Cache::get($cacheKey);
        if (!$cacheData || $isRefresh) {
            $cacheData = \App\Models\System\Permission::query()->select(['perm_id', 'parent_id','name','display_name', 'order_num', 'is_public'])->get();
            //附加上权限的角色数据
            $cacheData = $this->attachPermRoleData($cacheData);
            //装换为数组
            $cacheData = $cacheData ? $cacheData->toArray() : [];
            //以权限ID为KEY
            if ($cacheData){
                $newCacheData = [];
                foreach ($cacheData as $v){
                    //根据权限名缓存权限数据
                    $cacheKeyPermData = 'syspermission:permdata_simple:'.$v['name'];
                    Cache::put($cacheKeyPermData, $v, Carbon::now()->addMinutes(60));
                    //根据权限ID缓存权限数据
                    $cacheKeyPermData2 = 'syspermission:permdata_simple_id:'.$v['perm_id'];
                    Cache::put($cacheKeyPermData2, $v, Carbon::now()->addMinutes(60));

                    $newCacheData[(int) $v['perm_id']] = $v['name'];
                }
                $cacheData = $newCacheData;
            }
            Cache::put($cacheKey, $cacheData, Carbon::now()->addMinutes(60));
        }
        //附加上权限拥有角色列表
        return $cacheData;
    }
    /**
     * 获取轻巧版缓存key
     * @param $permId
     * @return mixed
     */
    public function getCacheSimplePermDataById($permId)
    {
        $cacheKeyPermData = 'syspermission:permdata_simple_id:'.$permId;
        $permData = Cache::get($cacheKeyPermData);
        if (empty($permData)){
            $cacheDataDb = \App\Models\System\Permission::query()->select(['perm_id', 'parent_id','name','display_name', 'order_num', 'is_public'])->find($permId);
            //附加上权限的角色数据
            if ($cacheDataDb) {
                $cacheDataDb = $this->attachPermRoleData(collect([$cacheDataDb]));
            }
            $permData = $cacheDataDb ? $cacheDataDb->first()->toArray() : [];
            //缓存
            Cache::put($cacheKeyPermData, $permData, Carbon::now()->addMinutes(60));
        }
        return $permData;
    }

    /**
     * 根据名称查询权限
     * @param $permName
     * @return array|mixed
     */
    public function getCacheSimplePermDataByName($permName)
    {
        $cacheKeyPermData = 'syspermission:permdata_simple:'.$permName;
        $permData = Cache::get($cacheKeyPermData);
        if (empty($permData)){
            $cacheDataDb = \App\Models\System\Permission::query()->where('name', $permName)->select(['perm_id', 'parent_id','name','display_name', 'order_num', 'is_public'])->first();
            //附加上权限的角色数据
            if ($cacheDataDb){
                $cacheDataDb = $this->attachPermRoleData(collect([$cacheDataDb]));
            }
            $permData = $cacheDataDb ? $cacheDataDb->first()->toArray() : [];
            //缓存
            Cache::put($cacheKeyPermData, $permData, Carbon::now()->addMinutes(60));
        }
        return $permData;
    }
    /**
     * 获取面包屑数据
     * @param $permId
     * @return array
     */
    public function getBreadcrumbData($permId)
    {
        //轻巧版
        $permSimpleList = $this->getCacheSimplePermList();
        $breadcrumbData = [];
        if ($permSimpleList && isset($permSimpleList[$permId])){
            while (isset($permSimpleList[$permId])){
                $permData = $this->getCacheSimplePermDataById($permId);
                if (!empty($permData)){
                    array_unshift($breadcrumbData, $permData);
                    $permId = (int) $permData['parent_id'];
                }else{
                    $permId = 0;
                }
            }
        }
        return $breadcrumbData;
        /*$permList = $this->getCachePermList();
        if ($permList && isset($permList[$permId])){
            while (isset($permList[$permId])){
                array_unshift($this->breadcrumbData, $permList[$permId]);
                $permId = (int) $permList[$permId]['parent_id'];
            }
        }
        return $this->breadcrumbData;*/
    }

    /**
     * 获取父级权限数据，用来定位当前选中菜单
     * @param $permId
     * @return array
     */
    public function getParentPermData($permId)
    {
        $parentPermData = [];
        $permList = $this->getCachePermList();
        if (isset($permList[$permId])){
            $curPermData = $permList[$permId];
            $parentPermId = (int) $curPermData['parent_id'];
            $parentPermData = isset($permList[$parentPermId]) ? $permList[$parentPermId] : [];
        }
        return $parentPermData;
    }
}
